package org.danger.t7.db.duplicate;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

/**
 * .
 */
@Slf4j
public class SaveAndDuplicateKeyUpdate extends AbstractMethod {

    /**
     * ..
     */
    @Getter
    @Setter
    public static final class FieldInfo {
        private String column;
        private Field field;
    }

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sql = "<script>INSERT INTO %s (%s) VALUES %s ON DUPLICATE KEY UPDATE %s</script>";
        List<TableFieldInfo> fieldList1 = tableInfo.getFieldList();
        List<FieldInfo> fieldList2 = new ArrayList<>();
        boolean hasId = false;
        for (TableFieldInfo f : fieldList1) {
            if (f.getColumn().equals(tableInfo.getKeyColumn())) {
                hasId = true;
            }
            FieldInfo fieldInfo = new FieldInfo();
            fieldInfo.column = f.getColumn();
            fieldInfo.field = f.getField();
            fieldList2.add(fieldInfo);
        }
        if (!hasId) {
            FieldInfo fieldInfo = new FieldInfo();
            fieldInfo.column = tableInfo.getKeyColumn();
            try {
                fieldInfo.field = modelClass.getDeclaredField(tableInfo.getKeyProperty());
                fieldInfo.field.setAccessible(true);
            } catch (NoSuchFieldException e) {
                throw new RuntimeException(e);
            }
            fieldList2.add(fieldInfo);
        }
        //生成所需的sql片段
        String fieldNames = "";
        for (int i = 0; i < fieldList2.size(); i++) {
            String camelName = fieldList2.get(i).getField().getName();
            String suffix = i < fieldList2.size() - 1 ? "," : "";
            fieldNames += String.format("<if test=\"%s != null\">%s%s</if>", camelName,
                    fieldList2.get(i).getColumn(), suffix);
        }
        String insertFields = "";
        for (int i = 0; i < fieldList2.size(); i++) {
            String camelName = fieldList2.get(i).getField().getName();
            String suffix = i < fieldList2.size() - 1 ? "," : "";
            insertFields += String.format("<if test=\"%s != null\">#{%s}%s</if>", camelName, camelName, suffix);
        }
        insertFields = "(" + insertFields + ")";
        String updateFields = "";
        for (int i = 0; i < fieldList2.size(); i++) {
            String camelName = fieldList2.get(i).getField().getName();
            String suffix = i < fieldList2.size() - 1 ? "," : "";
            boolean append = false;
            String appendSeparator = ",";
            Field field = fieldList2.get(i).getField();
            if (field.isAnnotationPresent(DuplicateUpdate.class)) {
                DuplicateUpdate du = field.getAnnotation(DuplicateUpdate.class);
                append = du.append();
                appendSeparator = du.appendSeparator();
            }
            if (!append) {
                updateFields += String.format("<if test=\"%s != null\">%s=values(%s)%s</if>",
                        camelName, fieldList2.get(i).getColumn(), fieldList2.get(i).getColumn(), suffix);
            } else if (fieldList2.get(i).getField().getType() == String.class) {
                updateFields += String.format("<if test=\"%s != null\">%s=concat(remark, '%s', values(%s))%s</if>",
                        camelName, fieldList2.get(i).getColumn(), appendSeparator,
                        fieldList2.get(i).getColumn(), suffix);
            } else {
                String s = "不支持非varchar字段的append模式 - "
                        + modelClass.getSimpleName() + "." + field.getName();
                log.error(s);
                throw new RuntimeException(s);
            }
        }
        //生成具体脚本
        String sqlResult = String.format(sql, tableInfo.getTableName(), fieldNames, insertFields, updateFields);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
        return this.addUpdateMappedStatement(mapperClass, modelClass, "saveAndDuplicateKeyUpdate", sqlSource);
    }

}
